package com.nehc.nettyserver.service.storage.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nehc.nettyserver.config.StorageConfig;
import com.nehc.nettyserver.service.storage.StorageService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

/**
 * JSON文件存储服务实现
 * 使用虚拟线程处理IO操作
 * 
 * @author NEHC
 * @date 2023-04-02
 */
@Slf4j
@Service
@Primary
@RequiredArgsConstructor
public class JsonStorageServiceImpl implements StorageService {
    
    private final StorageConfig storageConfig;
    private final ObjectMapper objectMapper;
    private final ExecutorService fileIoExecutor; // 使用虚拟线程执行器
    private Path storagePath;

    @PostConstruct
    public void init() throws IOException {
        // 创建存储目录
        storagePath = Paths.get(storageConfig.getLocation());
        if (!Files.exists(storagePath)) {
            Files.createDirectories(storagePath);
            log.info("创建存储目录: {}", storagePath);
        }
    }

    @Override
    public <T> boolean save(String id, T entity) throws IOException {
        String className = entity.getClass().getSimpleName().toLowerCase();
        Path classPath = storagePath.resolve(className);
        if (!Files.exists(classPath)) {
            Files.createDirectories(classPath);
        }
        
        Path filePath = classPath.resolve(id + ".json");
        objectMapper.writeValue(filePath.toFile(), entity);
        log.debug("保存对象: {}/{}", className, id);
        return true;
    }
    
    /**
     * 异步保存对象
     */
    @Async
    public <T> CompletableFuture<Boolean> saveAsync(String id, T entity) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return save(id, entity);
            } catch (IOException e) {
                log.error("异步保存对象失败: {}", id, e);
                return false;
            }
        }, fileIoExecutor);
    }

    @Override
    public <T> Optional<T> get(String id, Class<T> clazz) throws IOException {
        String className = clazz.getSimpleName().toLowerCase();
        Path filePath = storagePath.resolve(className).resolve(id + ".json");
        
        if (!Files.exists(filePath)) {
            return Optional.empty();
        }
        
        T entity = objectMapper.readValue(filePath.toFile(), clazz);
        return Optional.ofNullable(entity);
    }
    
    /**
     * 异步获取对象
     */
    @Async
    public <T> CompletableFuture<Optional<T>> getAsync(String id, Class<T> clazz) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return get(id, clazz);
            } catch (IOException e) {
                log.error("异步获取对象失败: {}", id, e);
                return Optional.<T>empty();
            }
        }, fileIoExecutor);
    }

    @Override
    public <T> List<T> getAll(Class<T> clazz) throws IOException {
        String className = clazz.getSimpleName().toLowerCase();
        Path classPath = storagePath.resolve(className);
        
        if (!Files.exists(classPath)) {
            return new ArrayList<>();
        }
        
        List<T> result = new ArrayList<>();
        Files.list(classPath)
                .filter(p -> p.toString().endsWith(".json"))
                .forEach(p -> {
                    try {
                        T entity = objectMapper.readValue(p.toFile(), clazz);
                        result.add(entity);
                    } catch (IOException e) {
                        log.error("读取文件失败: {}", p, e);
                    }
                });
        
        return result;
    }

    @Override
    public boolean delete(String id) throws IOException {
        // 这里需要确保id包含对象类型前缀
        if (!id.contains("/")) {
            log.error("删除失败，ID格式不正确: {}", id);
            return false;
        }
        
        String[] parts = id.split("/");
        String className = parts[0];
        String objectId = parts[1];
        
        Path filePath = storagePath.resolve(className).resolve(objectId + ".json");
        if (!Files.exists(filePath)) {
            return false;
        }
        
        Files.delete(filePath);
        log.debug("删除对象: {}", id);
        return true;
    }

    @Override
    public <T> boolean clear(Class<T> clazz) throws IOException {
        String className = clazz.getSimpleName().toLowerCase();
        Path classPath = storagePath.resolve(className);
        
        if (!Files.exists(classPath)) {
            return true;
        }
        
        Files.list(classPath)
                .filter(p -> p.toString().endsWith(".json"))
                .forEach(p -> {
                    try {
                        Files.delete(p);
                    } catch (IOException e) {
                        log.error("删除文件失败: {}", p, e);
                    }
                });
        
        log.info("清空对象: {}", className);
        return true;
    }

    @Override
    @Scheduled(fixedDelayString = "${spring.storage.backup.interval:3600000}")
    public boolean backup() throws IOException {
        if (!storageConfig.getBackup().isEnabled()) {
            return false;
        }
        
        // 使用虚拟线程异步执行备份操作
        CompletableFuture.runAsync(() -> {
            try {
                String timeStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
                Path backupPath = Paths.get(storageConfig.getLocation(), "backup", timeStr);
                
                if (!Files.exists(backupPath)) {
                    Files.createDirectories(backupPath);
                }
                
                // 递归复制所有文件
                Files.walk(storagePath)
                        .filter(p -> !p.equals(storagePath))
                        .filter(p -> !p.startsWith(storagePath.resolve("backup")))
                        .forEach(source -> {
                            Path dest = backupPath.resolve(storagePath.relativize(source));
                            try {
                                if (Files.isDirectory(source)) {
                                    if (!Files.exists(dest)) {
                                        Files.createDirectories(dest);
                                    }
                                } else {
                                    Files.copy(source, dest, StandardCopyOption.REPLACE_EXISTING);
                                }
                            } catch (IOException e) {
                                log.error("备份文件失败: {} -> {}", source, dest, e);
                            }
                        });
                
                log.info("数据备份完成: {}", backupPath);
            } catch (IOException e) {
                log.error("执行备份失败", e);
            }
        }, fileIoExecutor);
        
        return true;
    }
} 